
package com.eltonkent.db;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

import com.eltonkent.security.BFEncryptionEngine;
import com.eltonkent.ui.containers.SafeEntryContainer;
import com.eltonkent.ui.containers.TemplateFieldContainer;
import com.eltonkent.util.DateUtil;

public class SafeEntryTable extends GenericTable
{

	final static String TABLE_NAME = "TBL_SAFE_ENTRY";
	final static String COL_FOLDER_NAME = "FOLDER_NAME";
	private final static String COL_SAFE_ENTRIES = "SAFE_ENTRY";
	private final static String COL_CREATED_ON = "CREATED_ON";
	private final static String COL_ENTRY_UID = "UID";
	private final static String COL_ICON_ID = "ICON_ID";
	private final static String COL_ENTRY_NAME = "ENTRY_NAME";
	private final static String COL_ENTRY_TEMPLATE_NAME = "ENTRY_TEMPLATE_NAME";

	SafeEntryTable()
	{
	}

	public SafeEntryTable(Context context)
	{
		super(context);
	}

	private void addEntry(String folderName, String entryName, String entryTemplateName, byte[] entries,
			String iconId)
	{
		ContentValues safeEntryValues = new ContentValues();
		safeEntryValues
				.put(COL_CREATED_ON, DateUtil.getFormattedDate(new Date(System.currentTimeMillis())));
		safeEntryValues.put(COL_FOLDER_NAME, folderName);
		safeEntryValues.put(COL_ENTRY_NAME, entryName);
		safeEntryValues.put(COL_ENTRY_TEMPLATE_NAME, entryTemplateName);
		safeEntryValues.put(COL_SAFE_ENTRIES, entries);
		safeEntryValues.put(COL_ICON_ID, iconId);
		safeEntryValues.put(COL_ENTRY_UID, getUniqueID());

		getDatabase().insert(TABLE_NAME, null, safeEntryValues);
	}

	public void changeEntryFolder(String entryUID, String oldFolder, String newFolder)
	{
		ContentValues safeEntryValues = new ContentValues();
		safeEntryValues.put(COL_FOLDER_NAME, newFolder);
		getDatabase()
				.update(
						TABLE_NAME,
						safeEntryValues,
						COL_FOLDER_NAME + "='" + oldFolder + "' AND " + COL_ENTRY_UID + "='" + entryUID
								+ "'", null);
		closeDB();
	}

	public void deleteEntry(String entryUid, String folderName)
	{
		getDatabase().delete(TABLE_NAME,
				COL_ENTRY_UID + "='" + entryUid + "' AND " + COL_FOLDER_NAME + "='" + folderName + "'",
				null);
		closeDB();
	}

	@Override
	void doAfterTableCreate(SQLiteDatabase database)
	{
	}

	public Object[] getEntry(String entryUid, String folderName)
	{
		Cursor cursor = getDatabase().query(TABLE_NAME, new String[]
		{ COL_SAFE_ENTRIES, COL_CREATED_ON },
				COL_ENTRY_UID + "='" + entryUid + "' AND " + COL_FOLDER_NAME + "='" + folderName + "'",
				null, null, null, null);
		cursor.moveToFirst();
		String createdOn = cursor.getString(cursor.getColumnIndex(COL_CREATED_ON));
		byte[] data = cursor.getBlob(cursor.getColumnIndex(COL_SAFE_ENTRIES));
		data = BFEncryptionEngine.getInstance().decrypt(data);
		ByteArrayInputStream bis = new ByteArrayInputStream(data);
		DataInputStream dis = new DataInputStream(bis);
		int count = 0;
		ArrayList<TemplateFieldContainer> containerList = new ArrayList<TemplateFieldContainer>();
		try
		{
			count = dis.readInt();
			for(int i = 0; i < count; i++)
			{
				containerList.add(TemplateFieldContainer.readFromStream(dis));
			}
		} catch(IOException e)
		{
			e.printStackTrace();
		}
		// ArrayList<TemplateFieldContainer> containerList = new
		// ArrayList<TemplateFieldContainer>();

		cursor.close();
		closeDB();
		return new Object[]
		{ containerList, createdOn };
	}

	public SafeEntryContainer[] getSafeEntries(String folderName)
	{
		Cursor cursor = getDatabase().query(TABLE_NAME, new String[]
		{ COL_ENTRY_NAME, COL_ENTRY_TEMPLATE_NAME, COL_ENTRY_UID, COL_ICON_ID },
				COL_FOLDER_NAME + "='" + folderName + "'", null, null, null, null);
		SafeEntryContainer[] entries = new SafeEntryContainer[cursor.getCount()];
		cursor.moveToFirst();
		int indx = cursor.getColumnIndex(COL_ENTRY_NAME);
		int indx1 = cursor.getColumnIndex(COL_ENTRY_TEMPLATE_NAME);
		int indx2 = cursor.getColumnIndex(COL_ENTRY_UID);
		int indx3 = cursor.getColumnIndex(COL_ICON_ID);
		for(int i = 0; i < cursor.getCount(); i++)
		{
			entries[i] = new SafeEntryContainer(cursor.getString(indx), cursor.getString(indx1), cursor
					.getString(indx2), cursor.getString(indx3));
			cursor.moveToNext();

		}
		cursor.close();
		closeDB();
		return entries;
	}

	@Override
	List<Field> getTableFields()
	{
		List<Field> fields = new ArrayList<Field>();
		fields.add(new Field(COL_FOLDER_NAME, "text foreignkey"));
		fields.add(new Field(COL_ENTRY_NAME, "text"));
		fields.add(new Field(COL_ENTRY_TEMPLATE_NAME, "text"));
		fields.add(new Field(COL_SAFE_ENTRIES, "blob"));
		fields.add(new Field(COL_CREATED_ON, "text"));
		fields.add(new Field(COL_ENTRY_UID, "text"));
		fields.add(new Field(COL_ICON_ID, "text"));
		return fields;
	}

	@Override
	String getTableName()
	{
		return TABLE_NAME;
	}

	private String getUniqueID()
	{
		UUID uid = UUID.randomUUID();
		return String.valueOf(uid);
	}

	/**
	 * 
	 * @param entryFieldList
	 * @param folderName
	 * @param entryName
	 * @param entryTemplateName
	 * @param iconId
	 */
	public void saveEntry(ArrayList<TemplateFieldContainer> entryFieldList, String folderName,
			String entryName, String entryTemplateName, String iconId)
	{
		addEntry(folderName, entryName, entryTemplateName, serializeAndEncryptEntries(entryFieldList),
				iconId);
		closeDB();
	}

	private byte[] serializeAndEncryptEntries(ArrayList<TemplateFieldContainer> entryFieldList)
	{
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		DataOutputStream dos = new DataOutputStream(bos);
		int size = entryFieldList.size();
		try
		{
			dos.writeInt(size);
			for(int i = 0; i < size; i++)
			{
				entryFieldList.get(i).writeToStream(dos);
			}
			dos.close();
		} catch(IOException e)
		{
			e.printStackTrace();
		}
		byte[] encrypt = BFEncryptionEngine.getInstance().encrypt(bos.toByteArray());
		return encrypt;
	}

	public void updateEntry(ArrayList<TemplateFieldContainer> entryFieldList, String folderName,
			String templateUID)
	{
		ContentValues safeEntryValues = new ContentValues();
		safeEntryValues.put(COL_SAFE_ENTRIES, serializeAndEncryptEntries(entryFieldList));
		safeEntryValues
				.put(COL_CREATED_ON, DateUtil.getFormattedDate(new Date(System.currentTimeMillis())));
		getDatabase().update(TABLE_NAME, safeEntryValues,
				COL_FOLDER_NAME + "='" + folderName + "' AND " + COL_ENTRY_UID + "='" + templateUID + "'",
				null);
		closeDB();
	}

	void updateFolderName(String oldFolderName, String newFolderName)
	{
		ContentValues values = new ContentValues();
		values.put(COL_FOLDER_NAME, newFolderName);
	}

	@Override
	public void deSerialize(DataInputStream dis) throws IOException
	{
		getDatabase().delete(TABLE_NAME, null, null);
		int count = dis.readInt();
		for(int i = 0; i < count; i++)
		{
			ContentValues values = new ContentValues();
			values.put(COL_FOLDER_NAME, dis.readUTF());
			int len = dis.readInt();
			byte[] entry = new byte[len];
			dis.read(entry);
			values.put(COL_SAFE_ENTRIES, entry);
			values.put(COL_CREATED_ON, dis.readUTF());
			values.put(COL_ENTRY_UID, dis.readUTF());
			values.put(COL_ICON_ID, dis.readUTF());
			values.put(COL_ENTRY_NAME, dis.readUTF());
			values.put(COL_ENTRY_TEMPLATE_NAME, dis.readUTF());
			getDatabase().insert(TABLE_NAME, null, values);
		}
		closeDB();
	}

	@Override
	public void serialize(DataOutputStream dos) throws IOException
	{
		Cursor cursor = getDatabase().query(
				TABLE_NAME,
				new String[]
				{ COL_FOLDER_NAME, COL_SAFE_ENTRIES, COL_CREATED_ON, COL_ENTRY_UID, COL_ICON_ID,
						COL_ENTRY_NAME, COL_ENTRY_TEMPLATE_NAME }, null, null, null, null, null);
		cursor.moveToFirst();
		int idxName = cursor.getColumnIndex(COL_FOLDER_NAME);
		int idxEntries = cursor.getColumnIndex(COL_SAFE_ENTRIES);
		int idxCreated = cursor.getColumnIndex(COL_CREATED_ON);
		int idxUid = cursor.getColumnIndex(COL_ENTRY_UID);
		int idxIcon = cursor.getColumnIndex(COL_ICON_ID);
		int idxEntryName = cursor.getColumnIndex(COL_ENTRY_NAME);
		int idxTemplateName = cursor.getColumnIndex(COL_ENTRY_TEMPLATE_NAME);
		dos.writeInt(cursor.getCount());
		for(int i = 0; i < cursor.getCount(); i++)
		{
			dos.writeUTF(cursor.getString(idxName));
			byte[] entries = cursor.getBlob(idxEntries);
			dos.writeInt(entries.length);
			dos.write(entries);
			dos.writeUTF(cursor.getString(idxCreated));
			dos.writeUTF(cursor.getString(idxUid));
			dos.writeUTF(cursor.getString(idxIcon));
			dos.writeUTF(cursor.getString(idxEntryName));
			dos.writeUTF(cursor.getString(idxTemplateName));
			cursor.moveToNext();
		}
		cursor.close();
		closeDB();
	}
}
